package com.kmxd.ams.app.oss;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableSet;
import com.kmxd.ams.app.event.AmsEventPublisher;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.IArchiveWatermarkSvc;
import com.kmxd.ams.client.archive.vo.ArchiveTypeVO;
import com.kmxd.ams.client.archive.vo.ArchiveWatermarkVO;
import com.kmxd.ams.client.arrange.IDocumentSvc;
import com.kmxd.ams.client.event.efile.DocFileNumEvent;
import com.kmxd.ams.client.oss.IEfileRecordSvc;
import com.kmxd.ams.client.oss.dto.*;
import com.kmxd.ams.client.oss.vo.EfileRecordListVO;
import com.kmxd.ams.client.oss.vo.EfileRecordVO;
import com.kmxd.ams.client.system.ISysConfigSvc;
import com.kmxd.ams.client.system.ISysFondsSvc;
import com.kmxd.ams.client.system.vo.SysFondsVO;
import com.kmxd.ams.client.watermark.IWatermarkSvc;
import com.kmxd.ams.client.watermark.vo.WatermarkVO;
import com.kmxd.ams.core.common.constant.ArchConst;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.*;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.oss.bo.OssFile;
import com.kmxd.ams.core.oss.template.OssTemplate;
import com.kmxd.ams.core.util.*;
import com.kmxd.ams.infra.arrange.base.BaseBO;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.oss.entity.EfileRecord;
import com.kmxd.ams.infra.oss.mapper.EfileRecordMapper;
import com.kmxd.ams.infra.utils.EfileTableNameUtil;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

/**
 * 电子文件表 服务实现类
 *
 * @author ZuoLG
 * @since 2022-07-25
 */
@Slf4j
@Service
@AllArgsConstructor
public class EfileRecordSvcImpl extends ServiceImpl<EfileRecordMapper, EfileRecord>
    implements IEfileRecordSvc {

  private AmsEventPublisher amsEventPublisher;
  private EfileRecordMapper efileRecordMapper;
  private IArchiveTypeSvc archiveTypeSvc;
  private ISysFondsSvc sysFondsSvc;
  private ISysConfigSvc sysConfigSvc;
  private OssTemplate ossTemplate;
  private IWatermarkSvc watermarkSvc;

  @Override
  public Page<EfileRecordListVO> selectPage(Page reqPage, EfileRecordQueryDTO req) {
    if (ObjectUtil.isNotEmpty(req.getArchTypeId())) {
      ArchiveTypeVO archiveTypeVO = archiveTypeSvc.view(req.getArchTypeId());
      SysFondsVO sysFondsVO = sysFondsSvc.view(archiveTypeVO.getFondsId());
      String tableName = Constants.TABLE_NAME_EFILE + "_" + sysFondsVO.getAutoIndex();
      DynamicTableNameUtil.setTableName(tableName);
    }
    LambdaQueryWrapper<EfileRecord> queryWrapper =
        QueryGen.init(new QueryWrapper<EfileRecord>(), req).lambda();
    queryWrapper.orderByAsc(EfileRecord::getSort);
    Page<EfileRecord> page = efileRecordMapper.selectPage(reqPage, queryWrapper);
    Page<EfileRecordListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), EfileRecordListVO.class));

    MDC.put(ArchConst.ARCH_TYPE_ID, String.valueOf(req.getArchTypeId()));
    MDC.put(ArchConst.ARCH_ID, String.valueOf(req.getArchId()));
    return voPage;
  }

  @Override
  public List<EfileRecordListVO> selectList(EfileRecordQueryDTO req) {
    if (ObjectUtil.isNotEmpty(req.getArchTypeId())) {
      ArchiveTypeVO archiveTypeVO = archiveTypeSvc.view(req.getArchTypeId());
      SysFondsVO sysFondsVO = sysFondsSvc.view(archiveTypeVO.getFondsId());
      String tableName = Constants.TABLE_NAME_EFILE + "_" + sysFondsVO.getAutoIndex();
      DynamicTableNameUtil.setTableName(tableName);
    }
    LambdaQueryWrapper<EfileRecord> queryWrapper =
        QueryGen.init(new QueryWrapper<EfileRecord>(), req).lambda();
    queryWrapper.orderByAsc(EfileRecord::getSort);
    List<EfileRecord> list = efileRecordMapper.selectList(queryWrapper);

    MDC.put(ArchConst.ARCH_TYPE_ID, String.valueOf(req.getArchTypeId()));
    MDC.put(ArchConst.ARCH_ID, String.valueOf(req.getArchId()));
    return BeanUtil.copyToList(list, EfileRecordListVO.class);
  }

  /**
   * 限制文件后缀
   *
   * @param fileName
   * @return
   */
  private boolean checkFileSuffix(String fileName) {
    boolean flag = false;
    String suffix = FileUtil.getSuffix(fileName);
    // 获取转换的文件类型
    String ossExtend = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_EXTEND);
    List<String> exts = StrUtil.split(ossExtend, "|");
    if (CollUtil.contains(exts, suffix)) {
      flag = true;
    }
    return flag;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public EfileRecordVO upload(MultipartFile file, EfileRecordDTO recordDTO) throws Exception {
    if (!checkFileSuffix(file.getOriginalFilename())) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "当前文件格式不支持上传！");
    }

    String path = DateUtil.format(DateUtil.date(), "yyyy/MM/dd");
    path = getFondsPath(recordDTO, path);
    OssFile ossFile = ossTemplate.upload(file, OssEnum.collect, path);
    return upload(ossFile, recordDTO, file.getOriginalFilename());
  }

  private String getFondsPath(EfileRecordDTO recordDTO, String path) {
    // 全宗号，门类表名
    SysFondsVO fondsVO =
        sysFondsSvc.view(
            ObjectUtil.isNotEmpty(recordDTO.getFondsId())
                ? recordDTO.getFondsId()
                : SecurityUtil.getFondsId());
    ArchiveTypeVO archiveTypeVO = archiveTypeSvc.view(recordDTO.getArchTypeId());
    String fondsCodePath = "";
    if (ObjectUtil.isNotEmpty(fondsVO) && ObjectUtil.isNotEmpty(archiveTypeVO)) {
      fondsCodePath =
          ObjectUtil.isNotEmpty(recordDTO.getFondsCode())
              ? recordDTO.getFondsCode()
              : fondsVO.getCode();
    }
    return fondsCodePath
        + ossTemplate.separator()
        + archiveTypeVO.getDocTableId()
        + ossTemplate.separator()
        + path;
  }

  private EfileRecordVO upload(OssFile ossFile, EfileRecordDTO recordDTO, String fileName) {
    EfileRecord entity = BeanUtil.copyProperties(ossFile, EfileRecord.class);
    entity.setTitle(fileName);
    entity.setMd5Ecode(ossFile.getMd5());
    entity.setSm3(ossFile.getSm3());
    entity.setSaveFileName(ossFile.getName());
    entity.setFondsId(SecurityUtil.getFondsId());
    entity.setArchCode(recordDTO.getArchCode());
    entity.setArchId(recordDTO.getArchId());
    entity.setArchTypeId(recordDTO.getArchTypeId());
    entity.setFondsId(
        ObjectUtil.isNotNull(recordDTO.getFondsId())
            ? recordDTO.getFondsId()
            : SecurityUtil.getFondsId());
    entity.setDocType("");
    entity.setSort(1);
    entity.setOcrStatus(Constants.DEF_STATUS);
    entity.setIndexStatus(Constants.DEF_STATUS);
    entity.setMoveStatus(Constants.DEF_STATUS);
    entity.setTransferStatus(TransferStatusEnum.S1.getCode());

    String previewJson = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_PREVIEW);
    if (StrUtil.isNotBlank(previewJson) && JSONUtil.isTypeJSON(previewJson)) {
      try {
        JSONObject object = JSONUtil.parseObj(previewJson);
        String imgStr = object.getStr("img", "");
        String videoStr = object.getStr("video", "");
        List<String> imgs = IdUtil.split(imgStr, String.class);
        List<String> videos = IdUtil.split(videoStr, String.class);

        if (imgs.contains(entity.getExt()) || videos.contains(entity.getExt())) {
          entity.setTransferStatus(TransferStatusEnum.S3.getCode());
          entity.setShowExt(entity.getExt());
          entity.setShowFilePath(entity.getPath());
        }

      } catch (Exception e) {
        // 此处错误不影响上传，当前为为配置预览参数
        log.debug(e.getMessage());
      }
    }
    // 获取转换方式
    String transferConf = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_TRANSFER);
    // 转换后缀
    String transferExt = ConfigUtil.getVal(transferConf, ConfigConst.TRANSFER_EXT);

    // 如果当前目标与转换目标相同，修改显示文件
    if (ObjectUtil.equals(transferExt, entity.getExt())) {
      try {
        entity.setTransferStatus(TransferStatusEnum.S3.getCode());
        entity.setShowExt(entity.getExt());
        String showFilePath =
            ossFile.getPath().replace("." + entity.getExt(), "_show." + entity.getExt());
        FileUtil.copy(
            FileUtil.file(ossFile.getRootPath() + ossFile.getPath()),
            FileUtil.file(ossFile.getRootPath() + showFilePath),
            true);
        entity.setShowFilePath(showFilePath);
      } catch (IORuntimeException e) {
        e.printStackTrace();
        log.info("修改显示文件失败，不影响文件内容，不需要处理：" + e.getMessage());
      }
    }

    // 设置上传时的文件状态
    entity.setArrangeStatus(ArchStatusEnum.S0.getCode());
    entity.setHangingTime(DateUtil.date());
    entity.setDefPath(ossTemplate.getDefPath());
    this.baseMapper.insert(entity);

    BaseBO baseBO = BeanUtil.copyProperties(recordDTO, BaseBO.class);
    baseBO.setDocIds(recordDTO.getArchId().toString());
    // 发送事件更新电子文件
    amsEventPublisher.publishEvent(new DocFileNumEvent(baseBO));
    MDC.put(entity.getId().toString(), JSONUtil.toJsonStr(entity));
    return BeanUtil.copyProperties(entity, EfileRecordVO.class);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public EfileRecordVO upload(File file, EfileRecordDTO recordDTO) throws Exception {
    if (!checkFileSuffix(file.getName())) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "当前文件格式不支持上传！");
    }
    String path = DateUtil.format(DateUtil.date(), "yyyy/MM/dd");
    path = getFondsPath(recordDTO, path);
    OssFile ossFile = ossTemplate.upload(file, OssEnum.collect, path);
    return upload(ossFile, recordDTO, file.getName());
  }

  @Override
  public EfileRecordVO uploadTemp(MultipartFile file, EfileRecordDTO recordDTO) throws Exception {
    if (!checkFileSuffix(file.getOriginalFilename())) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "当前文件格式不支持上传！");
    }
    String path = DateUtil.format(DateUtil.date(), "yyyy/MM/dd");
    path = getFondsPath(recordDTO, path);
    OssFile ossFile = ossTemplate.upload(file, OssEnum.temp, path);
    EfileRecordVO entity = BeanUtil.copyProperties(ossFile, EfileRecordVO.class);
    entity.setTitle(file.getOriginalFilename());
    entity.setMd5Ecode(ossFile.getMd5());
    entity.setSm3(ossFile.getSm3());
    entity.setSaveFileName(ossFile.getName());
    entity.setFondsId(SecurityUtil.getFondsId());
    entity.setArchCode(recordDTO.getArchCode());
    entity.setArchId(recordDTO.getArchId());
    entity.setArchTypeId(recordDTO.getArchTypeId());
    entity.setFondsId(
        ObjectUtil.isNotNull(recordDTO.getFondsId())
            ? recordDTO.getFondsId()
            : SecurityUtil.getFondsId());
    entity.setDocType("1");
    entity.setSort(1);
    entity.setOcrStatus(Constants.DEF_STATUS);
    entity.setIndexStatus(Constants.DEF_STATUS);
    entity.setMoveStatus(Constants.DEF_STATUS);
    entity.setTransferStatus(TransferStatusEnum.S1.getCode());
    // 设置上传时的文件状态
    entity.setArrangeStatus(ArchStatusEnum.S0.getCode());
    entity.setHangingTime(DateUtil.date());
    entity.setFile(FileUtil.file(ossFile.getRootPath() + ossFile.getPath()));
    entity.setPath(ossFile.getRootPath() + ossFile.getPath());
    entity.setDefPath(ossTemplate.getDefPath());
    return entity;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    idList.forEach(
        item -> {
          EfileRecordVO recordVO = view(item);
          try {
            if (ObjectUtil.isNotNull(recordVO)) {

              String path =
                  getBasePathByArrangeStatus(recordVO.getDefPath(), recordVO.getArrangeStatus());
              ossTemplate.delete(path + recordVO.getPath());
              MDC.put(recordVO.getId().toString(), JSONUtil.toJsonStr(recordVO));
            }
          } catch (Exception e) {
            log.error(e.getMessage(), e);
          }
          this.baseMapper.deleteById(item);
          BaseBO baseBO = BeanUtil.copyProperties(recordVO, BaseBO.class);
          baseBO.setDocIds(recordVO.getArchId().toString());
          // 发送事件更新电子文件
          amsEventPublisher.publishEvent(new DocFileNumEvent(baseBO));
        });
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(Set<Long> ids) {
    ids.forEach(
        item -> {
          EfileRecordVO recordVO = view(item);
          if (ObjectUtil.isNotNull(recordVO)) {
            ossTemplate.delete(ossTemplate.getRootPath(recordVO.getDefPath()) + recordVO.getPath());
          }
          this.baseMapper.deleteById(item);
          BaseBO baseBO = BeanUtil.copyProperties(recordVO, BaseBO.class);
          baseBO.setDocIds(recordVO.getArchId().toString());
        });
  }

  @Override
  public void removeByDocIds(Set<Long> docIds) {
    List<EfileRecordListVO> list = selectListByDocIds(docIds);
    Set<Long> ids = list.stream().map(EfileRecordListVO::getId).collect(Collectors.toSet());
    remove(ids);
  }

  @Override
  public List<EfileRecordListVO> selectListByDocIds(Set<Long> docIds) {
    LambdaQueryWrapper<EfileRecord> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(EfileRecord::getArchId, docIds);
    List<EfileRecord> list = efileRecordMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, EfileRecordListVO.class);
  }

  @Override
  public List<EfileRecordListVO> selectListByDocIds(Long archTypeId, Set<Long> docIds) {
    LambdaQueryWrapper<EfileRecord> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(EfileRecord::getArchId, docIds);
    queryWrapper.eq(ObjectUtil.isNotEmpty(archTypeId), EfileRecord::getArchTypeId, archTypeId);
    ArchiveTypeVO archiveTypeVO = archiveTypeSvc.view(archTypeId);
    Long fondsId = archiveTypeVO.getFondsId();
    EfileTableNameUtil efileTableNameUtil = SpringUtil.getBean(EfileTableNameUtil.class);
    String tableName = efileTableNameUtil.getTableName(fondsId);
    DynamicTableNameUtil.setTableName(tableName);
    List<EfileRecord> list = efileRecordMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, EfileRecordListVO.class);
  }

  @Override
  public boolean archivingFile(Set<Long> docIds) {
    LambdaQueryWrapper<EfileRecord> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(EfileRecord::getArchId, docIds);
    List<EfileRecord> list = efileRecordMapper.selectList(queryWrapper);
    List<EfileRecord> docBatch =
        list.stream()
            .peek(
                item -> {
                  item.setArrangeStatus(ArchStatusEnum.S1.getCode());
                })
            .collect(Collectors.toList());
    return this.updateBatchById(docBatch);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(EfileRecordEditDTO req) {
    EfileRecord efileRecordDb = efileRecordMapper.selectById(req.getId());
    if (ObjectUtil.isNull(efileRecordDb)) {
      BizTipException.throwException(ErrorCode.EXCEPTION, "当前对象不存在！");
    }

    String path =
        getBasePathByArrangeStatus(efileRecordDb.getDefPath(), efileRecordDb.getArrangeStatus());
    String newPath = ossTemplate.rename(path + efileRecordDb.getPath(), req.getTitle());
    efileRecordDb.setTitle(req.getTitle());
    efileRecordDb.setSaveFileName(req.getTitle());
    efileRecordDb.setPath(newPath.replace(path, ""));
    if (CharSequenceUtil.isNotBlank(req.getDocType())) {
      efileRecordDb.setDocType(req.getDocType());
    }
    efileRecordMapper.updateById(efileRecordDb);

    MDC.put(efileRecordDb.getId().toString(), JSONUtil.toJsonStr(efileRecordDb));
  }

  @Override
  public EfileRecordVO view(Long id) {
    EfileRecord entity = efileRecordMapper.selectById(id);
    EfileRecordVO efileRecordVO = BeanUtil.copyProperties(entity, EfileRecordVO.class);
    File file =
        ossTemplate.getFile(
            getBasePathByArrangeStatus(efileRecordVO.getDefPath(), efileRecordVO.getArrangeStatus())
                + entity.getPath());
    efileRecordVO.setFile(file);
    MDC.put(entity.getId().toString(), JSONUtil.toJsonStr(entity));
    return efileRecordVO;
  }

  @Override
  public EfileRecordVO viewWatermarkFile(Long id) {
    EfileRecord entity = efileRecordMapper.selectById(id);
    EfileRecordVO efileRecordVO = BeanUtil.copyProperties(entity, EfileRecordVO.class);
    if (StrUtil.isBlank(efileRecordVO.getShowFilePath())) {
      return efileRecordVO;
    }
    File file =
        ossTemplate.getFile(
            getBasePathByArrangeStatus(efileRecordVO.getDefPath(), efileRecordVO.getArrangeStatus())
                + entity.getShowFilePath());
    efileRecordVO.setFile(file);
    MDC.put(entity.getId().toString(), JSONUtil.toJsonStr(entity));
    return efileRecordVO;
  }

  /**
   * 通过文件整理状态获得文件基础路径
   *
   * @param arrangeStatus
   * @return
   */
  @Override
  public String getBasePathByArrangeStatus(String defPath, Integer arrangeStatus) {
    return NumberUtil.equals(arrangeStatus, ArchStatusEnum.S1.getCode())
        ? ossTemplate.getManagePath(defPath)
        : ossTemplate.getCollectPath(defPath);
  }

  @Override
  public EfileRecordVO pdfPreview(Long id, Integer type, Boolean addWatermark) {
    if (ObjectUtil.isNull(type)) {
      type = UseTypeEnum.ONLINE_BROWSER.getType();
    }
    EfileRecord entity = efileRecordMapper.selectById(id);
    if (Objects.isNull(entity)) {
      return new EfileRecordVO();
    }
    EfileRecordVO efileRecordVO = BeanUtil.copyProperties(entity, EfileRecordVO.class);
    File file =
        ossTemplate.getFile(
            (getBasePathByArrangeStatus(
                    efileRecordVO.getDefPath(), efileRecordVO.getArrangeStatus()))
                + entity.getShowFilePath());

    efileRecordVO.setFile(file);

    if (BooleanUtil.isTrue(addWatermark)) {
      addWatermark(efileRecordVO, type);
    }

    MDC.put(entity.getId().toString(), JSONUtil.toJsonStr(entity));
    return efileRecordVO;
  }

  @Override
  public void addWatermark(EfileRecordVO vo, Integer type) {
    if (Objects.isNull(type)) {
      return;
    }
    IArchiveWatermarkSvc archiveWatermarkSvc = SpringUtil.getBean(IArchiveWatermarkSvc.class);
    ArchiveWatermarkVO watermarkVO = archiveWatermarkSvc.getByArchTypeId(vo.getArchTypeId());
    if (ObjectUtil.isNull(watermarkVO)) {
      return;
    }
    if (!BooleanUtil.isTrue(watermarkVO.getEnabled())) {
      return;
    }

    UseTypeEnum typeEnum = UseTypeEnum.getValue(type);
    if (Objects.isNull(typeEnum)) {
      return;
    }

    if (ImmutableSet.of(UseTypeEnum.ONLINE_BROWSER, UseTypeEnum.ONLINE_PRINT, UseTypeEnum.DOWNLOAD)
        .contains(typeEnum)) {
      addWatermark(vo);
    }
  }

  private void addWatermark(EfileRecordVO vo) {
    if (Objects.isNull(vo.getFile())) {
      return;
    }
    String basePath = ossTemplate.getSystemTempPath();
    String waterMarkPath = basePath + newFileNameAndPath(vo.getShowFilePath(), "wm", vo.getFile());

    String frontPath = StrUtil.replace(waterMarkPath, FileNameUtil.getName(waterMarkPath), "");
    if (!FileUtil.exist(frontPath)) {
      FileUtil.mkdir(frontPath);
    }

    String previewJson = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_PREVIEW);
    if (StrUtil.isNotBlank(previewJson) && JSONUtil.isTypeJSON(previewJson)) {
      try {
        JSONObject object = JSONUtil.parseObj(previewJson);
        String imgStr = object.getStr("img", "");
        String videoStr = object.getStr("video", "");
        List<String> imgs = IdUtil.split(imgStr, String.class);
        List<String> videos = IdUtil.split(videoStr, String.class);

        if (imgs.contains(vo.getExt()) || videos.contains(vo.getExt())) {
          // 此处是图片及视屏，不需要处理水印
        } else {
          WatermarkVO watermarkVO =
              watermarkSvc.addWatermark(vo.getArchTypeId(), vo.getFile(), waterMarkPath);
          if (Objects.nonNull(watermarkVO.getFile())) {
            vo.setFile(Optional.ofNullable(watermarkVO.getFile()).orElse(vo.getFile()));
            vo.setShowFilePath(
                Optional.ofNullable(watermarkVO.getPath()).orElse(vo.getShowFilePath()));
          }
        }
      } catch (Exception e) {
        // 此处错误不影响上传，当前为为配置预览参数
        log.debug(e.getMessage());
      }
    }
  }

  @Override
  public boolean updateSort(EfileSortDTO req) {
    List<Long> ids =
        req.getItemLists().stream().map(item -> item.getId()).collect(Collectors.toList());
    LambdaQueryWrapper<EfileRecord> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(EfileRecord::getId, ids);
    List<EfileRecord> list = efileRecordMapper.selectList(queryWrapper);
    List<EfileRecord> batchList =
        list.stream()
            .peek(
                item -> {
                  item.setSort(getSort(req, item.getId()));
                  MDC.put(item.getId().toString(), JSONUtil.toJsonStr(item));
                })
            .collect(Collectors.toList());
    this.updateBatchById(batchList);
    return true;
  }

  @Override
  public boolean efileMd5Check(EfileRecordEditDTO req) {
    if (ObjectUtil.isEmpty(req.getId())) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "ID不允许为空！");
    }
    EfileRecordVO recordVO = view(req.getId());
    if (ObjectUtil.isEmpty(recordVO.getMd5Ecode())) {
      return Boolean.TRUE;
    }
    File file =
        ossTemplate.getFile(
            (getBasePathByArrangeStatus(recordVO.getDefPath(), recordVO.getArrangeStatus()))
                + recordVO.getShowFilePath());
    String md5 = SecureUtils.md5(file);

    return ObjectUtil.equals(md5, recordVO.getMd5Ecode());
  }

  private int getSort(EfileSortDTO req, Long id) {
    List<EfileSortItemDTO> fieldSorts =
        req.getItemLists().stream()
            .filter(item -> item.getId().equals(id))
            .collect(Collectors.toList());
    return fieldSorts.isEmpty() ? 0 : fieldSorts.get(0).getSort();
  }

  @Override
  public OssFile exportZip(EfileRecordQueryDTO req) {
    Set<Long> idList = IdUtil.split(req.getIds());
    Set<Long> docIdList = IdUtil.split(req.getDocIds());
    Set<Long> volIdList = IdUtil.split(req.getVolIds());
    Set<Long> boxIdList = IdUtil.split(req.getBoxIds());
    LambdaQueryWrapper<EfileRecord> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(!idList.isEmpty(), EfileRecord::getId, idList);
    queryWrapper.in(!docIdList.isEmpty(), EfileRecord::getArchId, docIdList);
    if (!volIdList.isEmpty()) {
      ArchiveTypeVO archiveTypeVO = archiveTypeSvc.view(req.getArchTypeId());
      BaseBO baseBO = new BaseBO();
      baseBO.setTableId(archiveTypeVO.getDocTableId());
      baseBO.setVolIds(req.getVolIds());
      IDocumentSvc documentSvc = SpringUtil.getBean(IDocumentSvc.class);
      List<Document> documents = documentSvc.selectListByVolIds(baseBO, true);
      if (!documents.isEmpty()) {
        Set<Long> docIds = documents.stream().map(Document::getId).collect(Collectors.toSet());
        queryWrapper.in(!docIds.isEmpty(), EfileRecord::getArchId, docIds);
      }
    }
    if (!boxIdList.isEmpty()) {
      ArchiveTypeVO archiveTypeVO = archiveTypeSvc.view(req.getArchTypeId());
      BaseBO baseBO = new BaseBO();
      baseBO.setTableId(archiveTypeVO.getDocTableId());
      baseBO.setBoxIds(req.getBoxIds());
      IDocumentSvc documentSvc = SpringUtil.getBean(IDocumentSvc.class);
      List<Document> documents = documentSvc.selectListByBoxIds(baseBO, true);
      if (!documents.isEmpty()) {
        Set<Long> docIds = documents.stream().map(Document::getId).collect(Collectors.toSet());
        queryWrapper.in(!docIds.isEmpty(), EfileRecord::getArchId, docIds);
      }
    }
    List<EfileRecord> list = efileRecordMapper.selectList(queryWrapper);
    if (ObjectUtil.isEmpty(list)) {
      throw BizTipException.instance(ErrorCode.E_FILE_NOT_MOUNT, "当前档案未挂载电子文件!");
    }
    List<EfileRecordVO> recordList = BeanUtil.copyToList(list, EfileRecordVO.class);
    if (!BooleanUtil.isTrue(req.getOriginFlag())) {
      recordList.forEach(file -> addWatermark(file, UseTypeEnum.DOWNLOAD.getType()));
    }
    List<OssFile> paths =
        recordList.stream()
            .map(
                item -> {
                  OssFile ossFile = new OssFile();
                  ossFile.setRootPath(
                      getBasePathByArrangeStatus(item.getDefPath(), item.getArrangeStatus()));
                  if (BooleanUtil.isTrue(req.getOriginFlag())){
                    ossFile.setPath(item.getPath());
                    ossFile.setName(item.getSaveFileName());
                    ossFile.setExt(item.getExt());
                  }else {
                    ossFile.setPath(item.getShowFilePath());
                    ossFile.setName(FileUtil.getName(item.getShowFilePath()));
                    ossFile.setExt(FileUtil.extName(item.getShowFilePath()));
                  }

                  MDC.put(item.getId().toString(), JSONUtil.toJsonStr(item));
                  return ossFile;
                })
            .collect(Collectors.toList());
    return ossTemplate.exportZip(paths);
  }

  @Override
  public OssFile exportBatch(String ids, String docIds, String volIds) {
    Set<Long> idList = IdUtil.split(ids);
    Set<Long> docIdList = IdUtil.split(docIds);
    Set<Long> volIdList = IdUtil.split(volIds);
    LambdaQueryWrapper<EfileRecord> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(!idList.isEmpty(), EfileRecord::getId, idList);
    queryWrapper.in(!docIdList.isEmpty(), EfileRecord::getArchId, docIdList);
    List<EfileRecord> lists = efileRecordMapper.selectList(queryWrapper);
    List<OssFile> paths =
        lists.stream()
            .map(
                item -> {
                  OssFile ossFile = new OssFile();
                  ossFile.setRootPath(
                      getBasePathByArrangeStatus(item.getDefPath(), item.getArrangeStatus()));
                  ossFile.setPath(item.getPath());
                  ossFile.setName(item.getSaveFileName());
                  ossFile.setExt(item.getExt());
                  MDC.put(item.getId().toString(), JSONUtil.toJsonStr(item));
                  return ossFile;
                })
            .collect(Collectors.toList());
    if (paths.isEmpty()) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "当前档案未挂载电子文件！");
    }
    if (paths.size() == 1) {
      // 单个文件是返回
      OssFile ossFile = paths.get(0);
      File fileTmp = FileUtil.file(ossFile.getRootPath() + ossFile.getPath());
      ossFile.setFile(fileTmp);
      return ossFile;
    }
    return ossTemplate.exportZip(paths);
  }

  @Override
  public <T> T selectWithSummaryType(
      EfileRecordQueryDTO req,
      String tableId,
      String dbFieldKey,
      SummaryTypeEnum type,
      Class<T> clazz) {
    DynamicTableNameUtil.setTableName(tableId);
    String fieldName = StringUtils.underlineToCamel(dbFieldKey);
    QueryWrapper<EfileRecord> wrapper =
        Wrappers.<EfileRecord>query()
            .select(String.format("%s(%s) as %s", type.getFunc(), dbFieldKey, fieldName))
            .eq(
                Objects.nonNull(req.getFondsId()),
                FieldUtil.getColumn(EfileRecord::getFondsId),
                req.getFondsId())
            .eq(
                Objects.nonNull(req.getArchTypeId()),
                FieldUtil.getColumn(EfileRecord::getArchTypeId),
                req.getArchTypeId());
    EfileRecord record = efileRecordMapper.selectOne(wrapper);
    Map<String, Object> map = BeanUtil.beanToMap(record);
    if (Objects.nonNull(map) && map.containsKey(fieldName)) {
      return Convert.convert(clazz, map.get(fieldName));
    } else {
      return null;
    }
  }

  @Override
  public String newFileNameAndPath(String path, String suffixFileName, File file) {
    String fileSuffix = FileUtil.getSuffix(file);
    if (StrUtil.isEmpty(path) || StrUtil.isEmpty(fileSuffix)) {
      return path;
    }
    String newPath = path.substring(0, path.length() - (fileSuffix.length() + 1));
    return newPath + "-" + suffixFileName + "." + fileSuffix;
  }
}
